package com.service;

import com.constant.ConstantsEnum;
import com.exception.BusinessException;
import org.slf4j.LoggerFactory;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.WalletUtils;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.admin.Admin;
import org.web3j.protocol.admin.methods.response.PersonalUnlockAccount;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthGetBalance;
import org.web3j.protocol.core.methods.response.EthTransaction;
import org.web3j.protocol.core.methods.response.Transaction;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.Transfer;
import org.web3j.utils.Convert;

import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;

public class DappService {

    private final static org.slf4j.Logger logger = LoggerFactory.getLogger(DappService.class);

    public static Web3j web3j = null;
    public static Admin admin = null;

    static {
        HttpService httpService = new HttpService("http://192.168.1.89:8545/");
        web3j = Web3j.build(httpService);
        admin = Admin.build(httpService);
    }

    public static List<String> getAccountlist() {

        try {
            return web3j.ethAccounts().send().getAccounts();
        } catch (Throwable t) {
            logger.error("获取帐号失败", t);
            throw new BusinessException(ConstantsEnum.ERR_BUSINESS_EXCEPTION.getCode(), "获取帐号失败");
        }
    }

    public static boolean unLock(String account, String password) {
        PersonalUnlockAccount personalUnlockAccount = null;

        try {
            personalUnlockAccount = admin.personalUnlockAccount(account, password).sendAsync().get();
        } catch (Throwable t) {
            logger.error("解锁帐号失败", t);
            throw new BusinessException(ConstantsEnum.ERR_BUSINESS_EXCEPTION.getCode(), "解锁帐号失败");
        }

        if (personalUnlockAccount.accountUnlocked()) {
            return true;
        } else {
            return false;
        }
    }

    public static BigInteger getBalance(String account) {
        EthGetBalance ethGetBalance = null;
        try {
            ethGetBalance = web3j.ethGetBalance(account, DefaultBlockParameterName.LATEST).send();
        } catch (Throwable t) {
            logger.error("获取余额失败", t);
            throw new BusinessException(ConstantsEnum.ERR_BUSINESS_EXCEPTION.getCode(), "获取余额失败");
        }
        BigInteger balance = ethGetBalance.getBalance();
        return balance;
    }

    public static Credentials loadCredentials(File walletFile, String password) {
        Credentials credentials = null;
        try {
            credentials = WalletUtils.loadCredentials(password, walletFile);
            return credentials;
        } catch (Throwable t) {
            logger.error("获取Credentials失败", t);
            throw new BusinessException(ConstantsEnum.ERR_BUSINESS_EXCEPTION.getCode(), "获取Credentials失败，无法读取钱包文件");
        }
    }

    public static String transfer(String account, BigDecimal coin, File walletFile, String password) {
        Credentials credentials = null;
        try {
            credentials = WalletUtils.loadCredentials(password, walletFile);
        } catch (Throwable t) {
            logger.error("转账失败", t);
            throw new BusinessException(ConstantsEnum.ERR_BUSINESS_EXCEPTION.getCode(), "转账失败，无法读取钱包文件");
        }
        TransactionReceipt transactionReceipt = null;
        try {
            transactionReceipt = Transfer
                    .sendFunds(web3j, credentials, account, coin, Convert.Unit.ETHER).send();
            return transactionReceipt.getStatus();
        } catch (Throwable t) {
            logger.error("转账失败", t);
            throw new BusinessException(ConstantsEnum.ERR_BUSINESS_EXCEPTION.getCode(), "转账失败");
        }
    }

    public static Transaction qryTransaction(String transactionHash) {
        EthTransaction transaction = null;
        try {
            transaction = web3j.ethGetTransactionByHash(transactionHash)
                    .sendAsync().get();
            return transaction.getResult();
        } catch (Throwable t) {
            logger.error("获取转帐记录失败", t);
            throw new BusinessException(ConstantsEnum.ERR_BUSINESS_EXCEPTION.getCode(), "获取转帐记录失败");
        }
    }

    public static String createWallet(File walletFile, String password) {
        try {
            String wallet = WalletUtils.generateFullNewWalletFile(password, walletFile);
            return wallet;
        } catch (Throwable t) {
            logger.error("创建钱包失败", t);
            throw new BusinessException(ConstantsEnum.ERR_BUSINESS_EXCEPTION.getCode(), "创建钱包失败");
        }
    }

    public static String walletAddress(File walletFile, String password) {
        Credentials credentials = null;
        try {
            credentials = WalletUtils.loadCredentials(password, walletFile);
            return credentials.getAddress();
        } catch (Throwable t) {
            logger.error("从钱包取出账号失败", t);
            throw new BusinessException(ConstantsEnum.ERR_BUSINESS_EXCEPTION.getCode(), "从钱包取出账号失败");
        }
    }
}
